#include "common.h"
#include <sys/epoll.h>

#define MAX_EVENTS 5   //最大事件数
#define MAX_CLIENTS 5  //最多连接客户端数
#define SERVER_PORT 8888  //端口号
#define SAVE_DIR "./temp/server_file"
#define SEND_FILE_1 "./temp/server_file/tcp1.txt"
#define SEND_FILE_2 "./temp/server_file/udp1.txt"
#define TIMEOUT_MS 10000  //超时时间

// 客户端连接信息
typedef struct 
{
    int mfd;
    struct sockaddr_in maddr;
    socklen_t maddr_len;
    int mIs_busy; // 1表示正在处理，0表示空闲
    int mtransfer_type; //1:发送文件, 2:接收文件
} client_info_t;

client_info_t clients[MAX_CLIENTS] = {0};

/*******************************************************************
 简要描述：获取空闲客户端
 返回值：成功返回索引 失败返回-1
********************************************************************/
int get_free_client() 
{
    for (int i = 0; i < MAX_CLIENTS; i++) 
    {
        if (clients[i].mfd == 0) 
        {
            return i;
        }
    }
    return -1;
}

/*******************************************************************
 简要描述：查找客户端索引
 返回值：成功返回索引 失败返回-1
********************************************************************/
int find_client_index(int fd) 
{
    for (int i = 0; i < MAX_CLIENTS; i++) 
    {
        if (clients[i].mfd == fd) 
        {
            return i;
        }
    }
    return -1;
}


int main(int argc, char* argv[]) 
{
    int server_fd = -1;
    int epoll_fd = -1;
    int ret = EXIT_FAILURE;
    
    if (argc != 1) 
    {
        fprintf(stderr, "Input error!\n");
        goto cleanup;
    }
    
    // 创建UDP socket
    server_fd = socket(AF_INET, SOCK_DGRAM, 0);
    if (server_fd < 0) 
    {
        perror("socket err");
        goto cleanup;
    }
    
    // 端口复用
    int opt = 1;
    if (setsockopt(server_fd, SOL_SOCKET, SO_REUSEADDR, &opt, sizeof(opt)) < 0) 
    {
        perror("setsockopt err");
        goto cleanup;
    }
    
    printf("socket OK!\n");
    
    // 设置地址和端口
    struct sockaddr_in server_addr = 
    {
        .sin_family = AF_INET,
        .sin_port = htons(SERVER_PORT),
        .sin_addr.s_addr = INADDR_ANY
    };

    // 绑定
    if (bind(server_fd, (struct sockaddr*)&server_addr, sizeof(server_addr)) == -1) 
    {
        perror("bind err");
        goto cleanup;
    }
    printf("bind OK!\n");

    // 创建epoll实例
    epoll_fd = epoll_create1(0);
    if (epoll_fd == -1) 
    {
        perror("epoll_create1");
        goto cleanup;
    }
    
    // 添加服务器socket到epoll
    struct epoll_event ev;
    ev.events = EPOLLIN;
    ev.data.fd = server_fd;
    if (epoll_ctl(epoll_fd, EPOLL_CTL_ADD, server_fd, &ev) == -1) 
    {
        perror("epoll_ctl: server_fd");
        goto cleanup;
    }
    
    // 事件循环
    struct epoll_event events[MAX_EVENTS];
    printf("Server started, waiting for connections...\n");
    
    while (1) 
    {
        int nfds = epoll_wait(epoll_fd, events, MAX_EVENTS, TIMEOUT_MS);
        if (nfds == -1) 
        {
            perror("epoll_wait");
            break;
        }
        
        for (int i = 0; i < nfds; i++) 
        {
            // 服务器socket有数据可读
            if (events[i].data.fd == server_fd) 
            {
                char type_buf[2] = {0};
                struct sockaddr_in client_addr;
                socklen_t client_len = sizeof(client_addr);
                
                // 接收客户端发送的传输类型
                ssize_t read_len = recvfrom(server_fd, type_buf, 1, 0, 
                                           (struct sockaddr*)&client_addr, &client_len);
                
                if (read_len <= 0) 
                {
                    if (read_len == 0) 
                    {
                        printf("Client disconnected\n");
                    } 
                    else 
                    {
                        perror("recv type error");
                    }
                    continue;
                }
                
                // 添加到客户端列表
                int free_client = get_free_client();
                if (free_client == -1) 
                {
                    printf("Too many clients, rejecting connection\n");
                    continue;
                }
                
                clients[free_client].mfd = server_fd; // UDP使用同一个socket
                memcpy(&clients[free_client].maddr, &client_addr, client_len);
                clients[free_client].maddr_len = client_len;
                clients[free_client].mIs_busy = 0;
                clients[free_client].mtransfer_type = 0;
                
                printf("New client connected from %s:%d\n", 
                       inet_ntoa(client_addr.sin_addr), ntohs(client_addr.sin_port));
                
                // 根据客户端请求决定操作
                if (type_buf[0] == '1') // 客户端请求发送文件
                { 
                    printf("Receiving file from client %s:%d\n", 
                           inet_ntoa(client_addr.sin_addr), ntohs(client_addr.sin_port));
                    clients[free_client].mIs_busy = 1;
                    
                    if (recv_file(server_fd, SAVE_DIR, &client_addr, client_len) != 0) 
                    {
                        fprintf(stderr, "File receive failed from client\n");
                    }
                    
                    clients[free_client].mIs_busy = 0;
                } 
                else if (type_buf[0] == '2') // 客户端请求接收文件
                { 
                    printf("Sending file to client %s:%d\n", 
                           inet_ntoa(client_addr.sin_addr), ntohs(client_addr.sin_port));
                    clients[free_client].mIs_busy = 1;
                    
                    static int last_sent = 0;
                    const char *file_to_send = (last_sent++ % 2 == 0) ? SEND_FILE_1 : SEND_FILE_2;
                    if (send_file(server_fd, file_to_send, &client_addr, client_len) != 0) 
                    {
                        fprintf(stderr, "File send failed to client\n");
                    }
                    
                    clients[free_client].mIs_busy = 0;
                } 
                else 
                {
                    printf("Invalid transfer type from client: %c\n", type_buf[0]);
                }
                
                // 完成后清除客户端信息
                clients[free_client].mfd = 0;
                printf("Client %s:%d disconnected\n", 
                       inet_ntoa(client_addr.sin_addr), ntohs(client_addr.sin_port));
            }
        }
    }
    
    ret = EXIT_SUCCESS;

cleanup:
    if (epoll_fd != -1) 
    {
        close(epoll_fd);
    }
    if (server_fd != -1) 
    {
        close(server_fd);
    }
    return ret;
}